
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sched.h>
#include <assert.h>
#include <signal.h>
#include <time.h>
#include <stdint.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
// #include "gse_ex.h"

typedef int INT32;
typedef unsigned int UINT32;
typedef char INT8;
typedef char CHAR;
typedef unsigned char UINT8;
typedef short INT16;
typedef unsigned short UINT16;
typedef void VOID;

#define SSF_PART(x) 1
#define SPI_DEVICE    "/dev/spidev0.0"
#define SPI_BUFF_SIZE  32
#define SPI_HEAD_MAGIC  0xAACC
#define SPI_TAIL_MAGIC 0x55BB

#define SSF_INVERT16(x) \
            ((((x) & 0x00ff) << 8) | \
             (((x) & 0xff00) >> 8))

typedef struct jd_handle
{
    INT32 fd;
}JD_HANDLE;

typedef struct jd_spi_msg
{
    UINT16 head;
    UINT16 data[14];
    UINT16 tail;
}JD_SPI_MSG;

typedef struct jd_goose_to_spi
{
    UINT16 on_off;
    UINT16 active_power;
    UINT16 reactive_power;
    UINT16 active_power_change_rate;
    UINT16 reactive_power_change_rate;
}GOOSE_TO_SPI;

typedef struct jd_goose_from_spi
{
    UINT16 active_power;
    UINT16 reactive_power;
    UINT16 remaining_soc;
    UINT16 remaining_electric;
}GOOSE_FROM_SPI;

JD_HANDLE g_jd_handle;

#if SSF_PART("spi_test")

INT32 jd_spi_transfer(INT32 fd, UINT8* tx_buff, UINT8* rx_buff, UINT32 buff_len)
{
    INT32 ret = 0;
    struct spi_ioc_transfer transfer;

    transfer.rx_buf         = (UINT32)rx_buff;
    transfer.tx_buf         = (UINT32)tx_buff;
    transfer.len            = buff_len;
    transfer.speed_hz       = 20000000;
    transfer.delay_usecs    = 0;
    transfer.bits_per_word  = 8;

    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &transfer);

    if (ret < 1)
    {
        printf("can't send spi message!\n");
    }
    
    return ret;
}

INT32 jd_spi_send(JD_HANDLE* handle, UINT8* tx_buff)
{
    INT32 ret = -1;
    UINT8 rx_buff[SPI_BUFF_SIZE] = {0};
    
    ret = jd_spi_transfer(handle->fd, tx_buff, rx_buff, SPI_BUFF_SIZE);
    
    return ret;
}

INT32 jd_spi_create()
{
    INT32 ret   = 0;
    INT8 fd      = -1;
    UINT8 mode   = 0;
    UINT8 bits   = 0;
    UINT32 speed = 0;

    fd = open(SPI_DEVICE, O_RDWR);
    if (fd < 0)
    {
        printf("can't open device!\n");
        goto EXIT_LABEL;
    }

    /* spi mode */
    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
    if (ret == -1)
    {
        printf("can't set spi mode!\n");
        goto EXIT_LABEL;
    }
    
    ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
    if (ret == -1)
    {
        printf("can't get spi mode!\n");
        goto EXIT_LABEL;
    }

    /* bits per word */
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret == -1)
    {
        printf("can't set bits per word!\n");
        goto EXIT_LABEL;
    }
    
    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
    if (ret == -1)
    {
        printf("can't get bits per word!\n");
        goto EXIT_LABEL;
    }

    /* max speed hz */
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1)
    {
        printf("can't set max speed hz!\n");
        goto EXIT_LABEL;
    }
    
    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
    if (ret == -1)
    {
        printf("can't get max speed hz!\n");
        goto EXIT_LABEL;
    }

    printf("spi device: %s\n", SPI_DEVICE);
    printf("spi mode: %d\n", mode);
    printf("bits per word: %d\n", bits);
    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

EXIT_LABEL:
    return fd;
}

#endif

#if SSF_PART("sched")
UINT32 jd_process_sched_attr_set()
{
    UINT32 rc       = 0;
    INT32 policy    = SCHED_FIFO;
    struct sched_param param;  

    param.sched_priority = 80;  
    rc = sched_setscheduler(0, policy, &param);  
    if(0 != rc)
    {
        printf("sched_setscheduler error,rc=%d.\n", rc);
        goto EXIT_LABEL;
    }
    
EXIT_LABEL:  
    return rc;
}
UINT32 jd_process_sched_attr_get()
{
    UINT32 rc       = 0;
    INT32 policy    = 0;

    policy = sched_getscheduler(0);  

    printf ("process policy = %u.\n",policy);
    
EXIT_LABEL:  
    return rc;
}


UINT32 jd_pthread_sched_attr_set()
{
    UINT32 rc       = 0;
    INT32 policy    = SCHED_FIFO;
    UINT32 priority = 80;
    pthread_attr_t attr;
    struct sched_param sp;
    
    /* 初始化线程属性对�?*/
    rc = pthread_attr_init(&attr);
    if(0 != rc)
    {
        printf("pthread_attr_init error,rc=%d.\n", rc);
        goto EXIT_LABEL;
    }

    rc = pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
    if(0 != rc)
    {
        printf("pthread_attr_init error,rc=%d.\n", rc);
        goto EXIT_LABEL;
    }

    /* 设置调度策略 */
    rc = pthread_attr_setschedpolicy(&attr, policy);
    if(0 != rc)
    {
        printf("pthread_attr_setschedpolicy error, rc=%d.\n", rc);
        goto EXIT_LABEL;
    }

    /* 设置线程调度优先�?*/
    sp.sched_priority = priority;
    rc = pthread_attr_setschedparam(&attr, &sp);
    if(0 != rc)
    {
        printf("pthread_attr_setschedparam error,rc=%d.\n", rc);
        goto EXIT_LABEL;
    }

    rc = pthread_attr_getschedpolicy(&attr, &policy);
    if(0 != rc)
    {
        printf("pthread_attr_init error,rc=%d.\n", rc);
        goto EXIT_LABEL;
    }
    
    printf("pthread policy = %u.\n",policy);
    
    /* 销毁线程属�?*/
    rc = pthread_attr_destroy(&attr);
    if (0 != rc)
    {
        printf("pthread_attr_destroy failed,rc=%d.\n", rc);
        goto EXIT_LABEL;
    }
EXIT_LABEL:  
    return rc;
}

void  jd_posix_timer_cbk()
{
    #if 0
    time_t t;
    char p[32];
    time(&t);
    //strftime(p, sizeof(p), "%T", localtime(&t));
    strftime(p, sizeof(p), "%Y-%m-%d %H:%M:%S", localtime(&t));

    printf("@debug -----> date: %s \n", p);

    struct timeval tv;
    gettimeofday(&tv, NULL);
    
    printf("millisecond: %ld\n", tv.tv_sec * 1000 + tv.tv_usec / 1000);
    #endif
    UINT8 tx_buff[SPI_BUFF_SIZE] = {0};
    
    jd_spi_send(&g_jd_handle, tx_buff);
    
    
}


UINT32 jd_posix_timer_create()
{
    int ret;
    timer_t timer;
    struct sigevent evp;
    struct timespec spec;
    struct itimerspec time_value;

    evp.sigev_value.sival_ptr = &timer;
    /*��ʱ������ʱ�������һ���ź�*/
    evp.sigev_notify = SIGEV_SIGNAL; 
    evp.sigev_signo = SIGUSR1;
    signal(SIGUSR1, jd_posix_timer_cbk);

    /*ʱ��ԴѡCLOCK_MONOTONIC��Ҫ�ǿ��ǵ�ϵͳ��ʵʱʱ�ӿ��ܻ���
    �������й����и��ģ����Դ���һ���Ĳ�ȷ���ԣ���CLOCK_MONOTONIC
    �򲻻ᣬ��Ϊ�ȶ�*/
    ret = timer_create(CLOCK_MONOTONIC, &evp, &timer);
    if( ret )
        perror("timer_create");

    #if 1
    time_value.it_interval.tv_sec = 0;                  /*ÿ�봥��һ��*/
    time_value.it_interval.tv_nsec = 1000000;
    #else
    time_value.it_interval.tv_sec = 5;                  /*ÿ�봥��һ��*/
    time_value.it_interval.tv_nsec = 0;
    #endif
    clock_gettime(CLOCK_MONOTONIC, &spec);         
    time_value.it_value.tv_sec = spec.tv_sec + 0;      /*5�������*/
    time_value.it_value.tv_nsec = spec.tv_nsec + 0;

    ret = timer_settime(timer, CLOCK_MONOTONIC, &time_value, NULL);
    if( ret )
            perror("timer_settime");

}

VOID* jd_pthread_entry(VOID* cookie)
{
    jd_pthread_sched_attr_set();
    jd_posix_timer_create();
    
    while(1)
    {
        usleep(1);
    }
}

UINT32 jd_pthread_create()
{
    UINT32 rc       = 0;
    INT32 policy    = 0;
    pthread_t tid;

    rc = pthread_create(&tid, NULL, jd_pthread_entry, NULL);
    if (0 != rc)
    {
        printf("pthread_create failed,rc=%d.\n", rc);
        goto EXIT_LABEL;
    }

    
EXIT_LABEL:  
    return rc;
}
#endif


int main(int argc, char *argv[])
{
    
    jd_process_sched_attr_set();
    jd_process_sched_attr_get();

    g_jd_handle.fd = jd_spi_create();
    
    jd_posix_timer_create();
    
    //jd_pthread_create();
    
    while(1)
    {
        usleep(1);
    }
    
    return 0;
}

